/*                                  ATELIER                                   */

/* %%LICENSE_TAG%%                                                            */
package edu.gmu.view.canvas;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * Holds the Layers for an AnimatedComponent and notifies listeners
 * when changes occur.
 */
public class LayerModel
{   
    /**
     * Collection to hold our listeners.
     */
    protected Vector<LayerModelListener> layerModelListeners =
            new Vector<LayerModelListener>();
    
    /**
     * List of Layers.
     */
    protected List<Layer> layers = new ArrayList <Layer> ();
    
    /**
     * Creates a new LayerModel with default values.
     */   
    public LayerModel( )
    {
        
    }
    
    
    /**
     * Adds Layer to the model.
     *
     * @param newLayer
     */
    public void addLayer( Layer newLayer )
    {
        this.layers.add( newLayer );
        
        // Let our listeners know
        this.fireLayerModelChanged( LayerModelEvent.LAYERS_CHANGED );
    }
    
    /**
     * Adds Layers to the model.
     * 
     * 
     * @param newLayers
     */
    public void addLayers( List<Layer> newLayers )
    {
        this.layers.addAll( newLayers );
        
        // Let our listeners know
        this.fireLayerModelChanged( LayerModelEvent.LAYERS_CHANGED );
    }
    
    /**
     * Move layer to specified index.
     * 
     * 
     * @param layer
     * @param index
     * @return true if the move was successful
     */
    public boolean moveLayer( Layer layer, int index )
    {
        boolean moved = false;
        if( layer != null && (index > -1 && index < this.layers.size() ) )
        {
            //System.out.println( "Moved layer from " +
            //    this.layers.indexOf(layer) + " to " + index );
            
            // First remove - if this isn't a Layer in the model - ignore
            boolean isLayer = this.layers.remove( layer );
            if( isLayer == false )
            {
                return false;
            }
            
            // Now add/insert back into List
            this.layers.add( index, layer );
            
            moved = true;
            
            // Let our listeners know
            this.fireLayerModelChanged( LayerModelEvent.ORDER_CHANGED );
        }
        return moved;
    }
    
    /**
     * Gets layers from this Model.
     * 
     * @return List <Layer> layers
     */
    public List<Layer> getLayers( )
    {
        return this.layers;
    }

    /**
     * Gets the first layer from the model that is of the specified type
     * (there may certainly be more than one).
     * @param type
     * @return layer of type (null if none found)
     */
    public Layer getLayer( Class type )
    {
        Layer layer = null;
        for (int i = 0; i < layers.size(); i++)
        {
            Layer aLayer = this.layers.get(i);
            if( aLayer.getClass().equals(type) == true )
            {
                layer = aLayer;
                break;
            }
        }
        return layer;
    }
    
    /******************************* Event Methods ****************************/
    
    /*********************************************************************
     * Notify all listeners that have registered interest for notification
     * on this event.
     ********************************************************************
     * @param type
     */
    protected void fireLayerModelChanged( int type )
    {
        //Do this in order to only create Event once
        LayerModelEvent event = null;

        //Notify listeners last to first, notifying those that are interested
        for(int i = 0; i < this.layerModelListeners.size(); i++)
        {
            // lazy initialization
            if(event == null)
            {
                // Determine min and max freq
                event = new LayerModelEvent(  this,
                                              (long)System.currentTimeMillis(),
                                              type,
                                              this.layers
                                           );
            }
            // Get listener
            LayerModelListener listener =
                    ((LayerModelListener)this.layerModelListeners.get(i));
            // Call listener
            listener.layersChanged( event );
        }
    }
    
    /**
     * Adds LayerModelListener to list of listeners. First checks to see if
     * listener is already in list, if it is it does not add it a second time.
     * 
     * 
     * @param listener
     */
    public void addScanLayerModelListener( LayerModelListener listener )
    {
        if( !this.layerModelListeners.contains(listener) )
        {
            this.layerModelListeners.add(listener);
        }
    }

    /**
     * Removes LayerModelListener from list of listeners.
     * 
     * 
     * @param listener
     */
    public void removeScanLayerModelListener( LayerModelListener listener )
    {
        this.layerModelListeners.remove(listener);
    }
    
}

/*                                  ATELIER                                   */